package com.yang.demo.extensions;

import com.yang.core.api.RestClient;
import com.yang.core.api.RestClientBuilder;
import com.yang.core.plugins.loadbalancer.LoadBalancerExtension;
import com.yang.core.plugins.loadbalancer.LoadBalancerExtension.*;
import lombok.extern.slf4j.Slf4j;

import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 负载均衡扩展演示
 * 展示如何使用负载均衡扩展分发请求到多个服务器
 */
@Slf4j
public class LoadBalancerDemo {

    public static void main(String[] args) {
        System.out.println("=== 负载均衡扩展演示 ===\n");

        try {
            // 1. 轮询算法演示
            roundRobinDemo();

            // 2. 加权轮询算法演示
            weightedRoundRobinDemo();

            // 3. 随机算法演示
            randomDemo();

            // 4. 最少连接算法演示
            leastConnectionsDemo();

            // 5. IP哈希算法演示
            ipHashDemo();

            // 6. 一致性哈希算法演示
            consistentHashDemo();

            // 7. 健康检查演示
            healthCheckDemo();

            // 8. 会话亲和性演示
            sessionAffinityDemo();

        } catch (Exception e) {
            log.error("负载均衡演示执行失败", e);
        }
    }

    /**
     * 1. 轮询算法演示
     */
    private static void roundRobinDemo() {
        System.out.println("1. 轮询算法演示");
        System.out.println("=".repeat(50));

        // 创建服务器列表
        List<ServerInfo> servers = new java.util.ArrayList<>();
        servers.add(new ServerInfo("https://httpbin.org"));
        servers.add(new ServerInfo("https://jsonplaceholder.typicode.com"));
        servers.add(new ServerInfo("https://reqres.in"));

        // 创建负载均衡配置
        LoadBalancerConfig config = new LoadBalancerConfig();
        config.setEnabled(true);
        config.setAlgorithm(LoadBalancerAlgorithm.ROUND_ROBIN);
        config.setServers(servers);
        config.setMaxRetries(2);

        // 创建带有负载均衡的客户端
        RestClient client = RestClient.builder()
            .addExtension(new LoadBalancerExtension(config))
            .build();

        try {
            System.out.println("发送10个请求，观察轮询分发：");

            for (int i = 0; i < 10; i++) {
                try {
                    // 使用相对路径，负载均衡器会选择服务器
                    var response = client.get("/ip");
                    String server = extractServerFromResponse(response.getBody());
                    System.out.println("请求 " + (i + 1) + " -> " + server);

                    // 稍微延迟以便观察
                    Thread.sleep(100);
                } catch (Exception e) {
                    System.out.println("请求 " + (i + 1) + " 失败: " + e.getMessage());
                }
            }

        } finally {
            client.close();
        }

        System.out.println();
    }

    /**
     * 2. 加权轮询算法演示
     */
    private static void weightedRoundRobinDemo() {
        System.out.println("2. 加权轮询算法演示");
        System.out.println("=".repeat(50));

        // 创建带有不同权重的服务器列表
        List<ServerInfo> servers = new java.util.ArrayList<>();
        ServerInfo server1 = new ServerInfo("https://httpbin.org");
        server1.setWeight(3);
        servers.add(server1);

        ServerInfo server2 = new ServerInfo("https://jsonplaceholder.typicode.com");
        server2.setWeight(2);
        servers.add(server2);

        ServerInfo server3 = new ServerInfo("https://reqres.in");
        server3.setWeight(1);
        servers.add(server3);

        // 显示权重配置
        System.out.println("服务器权重配置：");
        servers.forEach(server ->
            System.out.println("  " + server.getUrl() + " (权重: " + server.getWeight() + ")"));

        // 创建负载均衡配置
        LoadBalancerConfig config = new LoadBalancerConfig();
        config.setEnabled(true);
        config.setAlgorithm(LoadBalancerAlgorithm.WEIGHTED_ROUND_ROBIN);
        config.setServers(servers);

        RestClient client = RestClient.builder()
            .addExtension(new LoadBalancerExtension(config))
            .build();

        try {
            System.out.println("\n发送12个请求，观察加权轮询分发：");

            for (int i = 0; i < 12; i++) {
                try {
                    var response = client.get("/ip");
                    String server = extractServerFromResponse(response.getBody());
                    System.out.println("请求 " + (i + 1) + " -> " + server);

                    Thread.sleep(100);
                } catch (Exception e) {
                    System.out.println("请求 " + (i + 1) + " 失败: " + e.getMessage());
                }
            }

        } finally {
            client.close();
        }

        System.out.println();
    }

    /**
     * 3. 随机算法演示
     */
    private static void randomDemo() {
        System.out.println("3. 随机算法演示");
        System.out.println("=".repeat(50));

        List<ServerInfo> servers = new java.util.ArrayList<>();
        servers.add(new ServerInfo("https://httpbin.org"));
        servers.add(new ServerInfo("https://jsonplaceholder.typicode.com"));
        servers.add(new ServerInfo("https://reqres.in"));

        LoadBalancerConfig config = new LoadBalancerConfig();
        config.setEnabled(true);
        config.setAlgorithm(LoadBalancerAlgorithm.RANDOM);
        config.setServers(servers);

        RestClient client = RestClient.builder()
            .addExtension(new LoadBalancerExtension(config))
            .build();

        try {
            System.out.println("发送10个请求，观察随机分发：");

            for (int i = 0; i < 10; i++) {
                try {
                    var response = client.get("/ip");
                    String server = extractServerFromResponse(response.getBody());
                    System.out.println("请求 " + (i + 1) + " -> " + server);

                    Thread.sleep(100);
                } catch (Exception e) {
                    System.out.println("请求 " + (i + 1) + " 失败: " + e.getMessage());
                }
            }

        } finally {
            client.close();
        }

        System.out.println();
    }

    /**
     * 4. 最少连接算法演示
     */
    private static void leastConnectionsDemo() {
        System.out.println("4. 最少连接算法演示");
        System.out.println("=".repeat(50));

        List<ServerInfo> servers = new java.util.ArrayList<>();
        servers.add(new ServerInfo("https://httpbin.org"));
        servers.add(new ServerInfo("https://jsonplaceholder.typicode.com"));
        servers.add(new ServerInfo("https://reqres.in"));

        LoadBalancerConfig config = new LoadBalancerConfig();
        config.setEnabled(true);
        config.setAlgorithm(LoadBalancerAlgorithm.LEAST_CONNECTIONS);
        config.setServers(servers);

        RestClient client = RestClient.builder()
            .addExtension(new LoadBalancerExtension(config))
            .build();

        try {
            System.out.println("发送异步请求，观察最少连接分发：");

            // 发送多个并发请求
            List<CompletableFuture<Void>> futures = Arrays.asList(
                sendAsyncRequest(client, 1),
                sendAsyncRequest(client, 2),
                sendAsyncRequest(client, 3),
                sendAsyncRequest(client, 4),
                sendAsyncRequest(client, 5),
                sendAsyncRequest(client, 6)
            );

            // 等待所有请求完成
            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        } finally {
            client.close();
        }

        System.out.println();
    }

    /**
     * 5. IP哈希算法演示
     */
    private static void ipHashDemo() {
        System.out.println("5. IP哈希算法演示");
        System.out.println("=".repeat(50));

        List<ServerInfo> servers = new java.util.ArrayList<>();
        servers.add(new ServerInfo("https://httpbin.org"));
        servers.add(new ServerInfo("https://jsonplaceholder.typicode.com"));
        servers.add(new ServerInfo("https://reqres.in"));

        LoadBalancerConfig config = new LoadBalancerConfig();
        config.setEnabled(true);
        config.setAlgorithm(LoadBalancerAlgorithm.IP_HASH);
        config.setServers(servers);

        RestClient client = RestClient.builder()
            .addExtension(new LoadBalancerExtension(config))
            .build();

        try {
            System.out.println("从不同客户端IP发送请求，观察IP哈希分发：");

            // 模拟不同的客户端IP
            String[] clientIPs = {
                "192.168.1.100",
                "192.168.1.101",
                "192.168.1.102",
                "192.168.1.100",  // 重复IP，应该分发到同一服务器
                "192.168.1.101",  // 重复IP，应该分发到同一服务器
                "192.168.1.103"
            };

            for (int i = 0; i < clientIPs.length; i++) {
                try {
                    // 设置X-Forwarded-For头模拟客户端IP
                    RestClient tempClient = RestClient.builder()
                        .addExtension(new LoadBalancerExtension(config))
                        .defaultHeader("X-Forwarded-For", clientIPs[i])
                        .build();

                    var response = tempClient.get("/ip");
                    String server = extractServerFromResponse(response.getBody());
                    System.out.println("客户端IP " + clientIPs[i] + " -> " + server);

                    tempClient.close();
                    Thread.sleep(100);
                } catch (Exception e) {
                    System.out.println("客户端IP " + clientIPs[i] + " 请求失败: " + e.getMessage());
                }
            }

        } finally {
            client.close();
        }

        System.out.println();
    }

    /**
     * 6. 一致性哈希算法演示
     */
    private static void consistentHashDemo() {
        System.out.println("6. 一致性哈希算法演示");
        System.out.println("=".repeat(50));

        List<ServerInfo> servers = new java.util.ArrayList<>();
        servers.add(new ServerInfo("https://httpbin.org"));
        servers.add(new ServerInfo("https://jsonplaceholder.typicode.com"));
        servers.add(new ServerInfo("https://reqres.in"));

        LoadBalancerConfig config = new LoadBalancerConfig();
        config.setEnabled(true);
        config.setAlgorithm(LoadBalancerAlgorithm.CONSISTENT_HASH);
        config.setServers(servers);

        RestClient client = RestClient.builder()
            .addExtension(new LoadBalancerExtension(config))
            .build();

        try {
            System.out.println("发送请求到不同路径，观察一致性哈希分发：");

            // 使用不同的请求路径
            String[] paths = {"/user/1", "/user/2", "/user/3", "/user/1", "/user/2", "/user/4"};

            for (int i = 0; i < paths.length; i++) {
                try {
                    // 一致性哈希应该将相同路径的请求分发到同一服务器
                    var response = client.get(paths[i]);
                    String server = extractServerFromResponse(response.getBody());
                    System.out.println("路径 " + paths[i] + " -> " + server);

                    Thread.sleep(100);
                } catch (Exception e) {
                    System.out.println("路径 " + paths[i] + " 请求失败: " + e.getMessage());
                }
            }

        } finally {
            client.close();
        }

        System.out.println();
    }

    /**
     * 7. 健康检查演示
     */
    private static void healthCheckDemo() {
        System.out.println("7. 健康检查演示");
        System.out.println("=".repeat(50));

        // 混合健康和不健康的服务器
        List<ServerInfo> servers = new java.util.ArrayList<>();
        servers.add(new ServerInfo("https://httpbin.org"));           // 健康
        servers.add(new ServerInfo("https://nonexistent-server.xyz")); // 不健康
        servers.add(new ServerInfo("https://jsonplaceholder.typicode.com")); // 健康

        LoadBalancerConfig config = new LoadBalancerConfig();
        config.setEnabled(true);
        config.setAlgorithm(LoadBalancerAlgorithm.ROUND_ROBIN);
        config.setServers(servers);

        // 配置健康检查
        config.setHealthCheckEnabled(true);
        config.setHealthCheckInterval(5000);  // 5秒间隔

        RestClient client = RestClient.builder()
            .addExtension(new LoadBalancerExtension(config))
            .build();

        try {
            System.out.println("等待健康检查完成...");
            try {
                Thread.sleep(6000); // 等待健康检查
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.out.println("健康检查等待被中断");
            }

            System.out.println("发送请求，观察只有健康服务器被使用：");

            for (int i = 0; i < 6; i++) {
                try {
                    var response = client.get("/ip");
                    String server = extractServerFromResponse(response.getBody());
                    System.out.println("请求 " + (i + 1) + " -> " + server + " (健康服务器)");

                    Thread.sleep(500);
                } catch (Exception e) {
                    System.out.println("请求 " + (i + 1) + " 失败: " + e.getMessage());
                }
            }

        } finally {
            client.close();
        }

        System.out.println();
    }

    /**
     * 8. 会话亲和性演示
     */
    private static void sessionAffinityDemo() {
        System.out.println("8. 会话亲和性演示");
        System.out.println("=".repeat(50));

        List<ServerInfo> servers = new java.util.ArrayList<>();
        servers.add(new ServerInfo("https://httpbin.org"));
        servers.add(new ServerInfo("https://jsonplaceholder.typicode.com"));
        servers.add(new ServerInfo("https://reqres.in"));

        LoadBalancerConfig config = new LoadBalancerConfig();
        config.setEnabled(true);
        config.setAlgorithm(LoadBalancerAlgorithm.ROUND_ROBIN);
        config.setServers(servers);

        // 启用会话亲和性
        config.setStickySession(true);
        config.setStickySessionHeader("JSESSIONID");

        RestClient client = RestClient.builder()
            .addExtension(new LoadBalancerExtension(config))
            .defaultHeader("Cookie", "JSESSIONID=session123")  // 模拟会话Cookie
            .build();

        try {
            System.out.println("使用相同会话ID发送多个请求：");

            for (int i = 0; i < 5; i++) {
                try {
                    var response = client.get("/ip");
                    String server = extractServerFromResponse(response.getBody());
                    System.out.println("请求 " + (i + 1) + " -> " + server + " (相同会话)");

                    Thread.sleep(100);
                } catch (Exception e) {
                    System.out.println("请求 " + (i + 1) + " 失败: " + e.getMessage());
                }
            }

            // 使用不同的会话ID
            RestClient client2 = RestClient.builder()
                .addExtension(new LoadBalancerExtension(config))
                .defaultHeader("Cookie", "JSESSIONID=session456")  // 不同的会话Cookie
                .build();

            System.out.println("\n使用不同会话ID发送请求：");

            try {
                var response = client2.get("/ip");
                String server = extractServerFromResponse(response.getBody());
                System.out.println("新会话请求 -> " + server);

                client2.close();
            } catch (Exception e) {
                System.out.println("新会话请求失败: " + e.getMessage());
            }

        } finally {
            client.close();
        }

        System.out.println();
    }

    /**
     * 发送异步请求
     */
    private static CompletableFuture<Void> sendAsyncRequest(RestClient client, int requestId) {
        return CompletableFuture.runAsync(() -> {
            try {
                var response = client.get("/ip");
                String server = extractServerFromResponse(response.getBody());
                System.out.println("异步请求 " + requestId + " -> " + server);
            } catch (Exception e) {
                System.out.println("异步请求 " + requestId + " 失败: " + e.getMessage());
            }
        });
    }

    /**
     * 从响应中提取服务器信息
     */
    private static String extractServerFromResponse(String response) {
        // 简单地从URL中提取服务器标识
        if (response.contains("httpbin.org")) {
            return "httpbin.org";
        } else if (response.contains("jsonplaceholder")) {
            return "jsonplaceholder.typicode.com";
        } else if (response.contains("reqres.in")) {
            return "reqres.in";
        } else {
            return "unknown";
        }
    }
}